import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableModel;

import org.rsbot.bot.Bot;
import org.rsbot.client.input.Canvas;
import org.rsbot.event.listeners.PaintListener;
import org.rsbot.script.Calculations;
import org.rsbot.script.Methods;
import org.rsbot.script.Script;
import org.rsbot.script.ScriptManifest;
import org.rsbot.script.wrappers.RSArea;
import org.rsbot.script.wrappers.RSCharacter;
import org.rsbot.script.wrappers.RSInterface;
import org.rsbot.script.wrappers.RSInterfaceChild;
import org.rsbot.script.wrappers.RSItemTile;
import org.rsbot.script.wrappers.RSNPC;
import org.rsbot.script.wrappers.RSObject;
import org.rsbot.script.wrappers.RSPlayer;
import org.rsbot.script.wrappers.RSTile;

// zzSleepzz's handiwork:
// - Turns off prayer when running between portals.
// - Doesn't turn on prayer until commencing an attack.
// - Auto-detects the boat to used based on the nearest NPC
// - Changed checkboxes to default to attack spinners/portals
// - Added checkbox for attacking brawlers, defaulted to off cuz only
//   noobs attack the brawlers in intermed/veteran games.
// - Smartened up the logic for selecting monsters to attack
// - Added status line to proggy
/**
 * Created by IntelliJ IDEA. User: Bool Date: 30-okt-2009 Time: 23:39:10
 */
@ScriptManifest(authors = {"Bool"},
category = "Minigame",
        name = "zzBPestControlV2",
        version = 2.10,
        description = "<html><style type='text/css'>"
        + "body {background:url('http://runedev-infinity.org/client/images/back_2.png') repeat}"
        + "</style><html><head><center><img src=\"http://runedev-infinity.org/client/images/logo.png\">"
        + "<h1><center><font color=#FFFFFF>"
        + "BPestControlV2 by; Bool<br />"
        + "MOD by; zzSleepzz"
        + "</center></font color></h1>"
        + "</head><br><body>"
        + "<center><table border=0 cellpadding=1 cellspacing=1 style=border-collapse:collapse width=80% id=AutoNumber1 bgcolor=CCCCCC>"
        + "<td width=90% align=justify>"
        + "<font size=2><center><font color=#0000FF>How to set up and start this script.</font></font size></center>"
        + "<font size=3>All of the set up options are in the GUI. Select your account you want to use "
        + "and press OK to show the GUI...<br>"
        + "<center><font color=#0000FF>Good luck and bot safe</font></center></font size>"
        + "</td></tr></table><br />"
        )
public class zzBPestControlV2 extends Script implements PaintListener {

    private final boolean debug = false;

    private void debug(final String s) {
        if (debug) {
            log(s);
        }
    }
    ScriptManifest sm = getClass().getAnnotation(ScriptManifest.class);
    double version = sm.version();
    private static final int SQUIRE_NOVICE = 3802;
    private static final int SQUIRE_INTERMED = 6140;
    private static final int SQUIRE_VETERAN = 6141;

    class animationChecker implements Runnable {

        public void run() {
            while (isActive) {
                if (me.getAnimation() != -1) {
                    lastAniChange = System.currentTimeMillis();
                }
                try {
                    Thread.sleep(500);
                } catch (final Exception ignored) {
                }
            }
        }
    }

    class BGUI extends JFrame implements ActionListener {

        /**
         *
         */
        private static final long serialVersionUID = 2490841282567788805L;
        private JPanel contentPane;
        private JTabbedPane tabbedPane;
        private JTable table;
        private JTextField textField;
        private JTextField textField_1;
        private JButton btnAddBreak;
        private DefaultTableModel model;
        private DefaultListModel jobmodel;
        private JButton btnAddAntiban;
        private JComboBox comboBox_1;
        private JList list_1;
        private JButton btnAddJob;
        private JList list;
        private JComboBox comboBox;

        public BGUI() {
            initGUI();
        }

        private void initGUI() {
            setAlwaysOnTop(true);
            setResizable(false);
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (final Exception e) {
            }
            setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            setBounds(100, 100, 450, 288);
            contentPane = new JPanel();
            contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
            setContentPane(contentPane);
            contentPane.setLayout(null);
            tabbedPane = new JTabbedPane(SwingConstants.LEFT);
            tabbedPane.setBounds(10, 10, 414, 218);
            contentPane.add(tabbedPane);

            final JPanel panel = new JPanel();
            tabbedPane.addTab("Main", null, panel, null);

            btnStartScript = new JButton("Start script");
            btnStartScript.addActionListener(this);
            btnStartScript.setBounds(327, 234, 97, 23);
            contentPane.add(btnStartScript);
            panel.setLayout(null);

            final JPanel panel_2 = new JPanel();
            tabbedPane.addTab("Antiban", null, panel_2, null);

            chckbxUseSpecialAttack = new JCheckBox("Use special attack");
            chckbxUseSpecialAttack.setBounds(10, 10, 126, 17);
            panel.add(chckbxUseSpecialAttack);

            chckbxUseQuickPrayer = new JCheckBox("Use quick prayer");
            chckbxUseQuickPrayer.setSelected(true);
            chckbxUseQuickPrayer.setBounds(10, 27, 126, 17);
            panel.add(chckbxUseQuickPrayer);

            comboBox = new JComboBox();
            comboBox.setModel(new DefaultComboBoxModel(jobsStrings));
            comboBox.setBounds(10, 50, 126, 24);
            panel.add(comboBox);

            btnAddJob = new JButton("Add Job");
            btnAddJob.setBounds(20, 80, 103, 23);
            btnAddJob.addActionListener(this);
            panel.add(btnAddJob);

            final JScrollPane scrollPane = new JScrollPane();
            scrollPane.setBounds(180, 10, 126, 193);
            panel.add(scrollPane);

            jobmodel = new DefaultListModel();
            list = new JList(jobmodel);
            scrollPane.setViewportView(list);
            list.setBorder(new TitledBorder(null, "", TitledBorder.LEADING,
                    TitledBorder.TOP, null, null));

            final JPanel panel_7 = new JPanel();
            tabbedPane.addTab("Break handler", null, panel_7, null);
            panel_2.setLayout(null);
            m = new DefaultListModel();
            list_1 = new JList(m);
            list_1.setBorder(new LineBorder(new Color(0, 0, 0)));
            list_1.setBounds(10, 10, 307, 164);
            panel_2.add(list_1);

            btnAddAntiban = new JButton("Add antiban");
            btnAddAntiban.addActionListener(this);
            btnAddAntiban.setBounds(10, 180, 97, 23);
            panel_2.add(btnAddAntiban);

            comboBox_1 = new JComboBox();
            comboBox_1.setModel(new DefaultComboBoxModel(new String[]{
                        "rotate compass", "move mouse",
                        "move mouse and rotate compass", "rest",
                        "right click object", "right click npc",
                        "right click player"}));
            comboBox_1.setBounds(113, 180, 204, 23);
            panel_2.add(comboBox_1);
            panel_7.setLayout(null);

            table = new JTable();
            table.setBorder(new LineBorder(new Color(0, 0, 0)));
            table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            table.setBounds(10, 10, 301, 164);
            model = new DefaultTableModel();
            table.setModel(model);
            model.addColumn("");
            model.addColumn("");
            panel_7.add(table);

            btnAddBreak = new JButton("Add break");
            btnAddBreak.addActionListener(this);
            btnAddBreak.setBounds(10, 180, 89, 23);
            panel_7.add(btnAddBreak);

            final JLabel lblBreakFor = new JLabel("Break for");
            lblBreakFor.setBounds(105, 183, 52, 16);
            panel_7.add(lblBreakFor);

            textField = new JTextField();
            textField.setBounds(158, 181, 27, 21);
            panel_7.add(textField);
            textField.setColumns(10);

            final JLabel lblAfter = new JLabel("after ");
            lblAfter.setBounds(190, 183, 27, 16);
            panel_7.add(lblAfter);

            textField_1 = new JTextField();
            textField_1.setBounds(218, 181, 26, 21);
            panel_7.add(textField_1);
            textField_1.setColumns(10);

            btnRemove = new JButton("Delete");
            btnRemove.addActionListener(this);
            btnRemove.setBounds(248, 181, 65, 23);
            panel_7.add(btnRemove);

            chckbxAttackPortals = new JCheckBox("Attack portals");
            chckbxAttackPortals.setSelected(true);
            chckbxAttackPortals.setBounds(10, 136, 105, 17);
            panel.add(chckbxAttackPortals);

            specialtxt = new JTextField();
            specialtxt.setText("  %");
            specialtxt.setBounds(137, 10, 31, 19);
            panel.add(specialtxt);
            specialtxt.setColumns(10);
            chckbxattackspinners = new JCheckBox("Attack spinners");
            chckbxattackspinners.setSelected(true);
            chckbxattackspinners.setBounds(10, 148, 113, 17);
            panel.add(chckbxattackspinners);


            chckbxAttackBrawlers = new JCheckBox("Attack brawlers");
            chckbxAttackBrawlers.setSelected(false);
            chckbxAttackBrawlers.setBounds(10, 160, 105, 17);
            panel.add(chckbxAttackBrawlers);
        }
        DefaultListModel m;
        private JButton btnRemove;

        public void actionPerformed(final ActionEvent e) {
            if (e.getSource() == btnStartScript) {
                start = true;
                attackBrawlers = chckbxAttackBrawlers.isSelected();
                attackBrawlers = chckbxAttackBrawlers.isSelected();
                attackSpinner = chckbxattackspinners.isSelected();
                if (pickupArrows) {
                    if (getCurrentTab() != TAB_EQUIPMENT) {
                        openTab(TAB_EQUIPMENT);
                    }
                    arrowID = getEquipmentArray()[13];
                }
                if (DBaxe) {
                    if (getCurrentTab() != TAB_EQUIPMENT) {
                        openTab(TAB_EQUIPMENT);
                    }
                    oldID = getEquipmentArray()[3];
                }
                usePray = chckbxUseQuickPrayer.isSelected();
                if (chckbxUseSpecialAttack.isSelected()) {
                    try {
                        specialPercent = Integer.parseInt(specialtxt.getText());
                    } catch (final Exception check) {
                        specialPercent = 0;
                    }
                } else {
                    specialPercent = 0;
                }
                for (int i = 0; i < jobmodel.getSize(); i++) {
                    int index = 0;
                    for (int j = 0; j < jobsStrings.length; j++) {
                        if (jobsStrings[j].equals(jobmodel.get(i).toString())) {
                            index = j;
                        }
                    }
                    jobQ.add(new Job(jobmodel.get(i).toString(),
                            jobsPoints[index]));
                }
                for (int i = 0; i < m.getSize(); i++) {
                    antibanQ.add(m.get(i).toString());
                }

                dispose();
            }
            if (e.getSource() == btnAddJob) {
                jobmodel.addElement(comboBox.getSelectedItem());
            }
            if (e.getSource() == btnRemove) {
                if (table.getSelectedRow() != -1) {
                    model.removeRow(table.getSelectedRow());
                }
            }
            if (e.getSource() == btnAddAntiban) {
                m.addElement(comboBox_1.getSelectedItem());
            }
            if (e.getSource() == btnAddBreak) {
                model.addRow(new Object[]{textField.getText(),
                            textField_1.getText()});
            }
        }
        double version = 1.0;
        private JTextField specialtxt;
        private JButton btnStartScript;
        private JCheckBox chckbxUseSpecialAttack;
        private JCheckBox chckbxUseQuickPrayer;
        private JCheckBox chckbxAttackPortals;
        private JCheckBox chckbxAttackBrawlers;
        private JCheckBox chckbxattackspinners;
    }

    private class Job {

        private final String n;
        private final boolean done = false;
        public int points;

        public Job(final String name, final int points) {
            n = name;
            this.points = points;
        }

        public final String getName() {
            return n;
        }

        public boolean isFinished() {
            return done;
        }

        @Override
        public String toString() {
            return "Name " + getName();
        }
    }

    private class Portal {

        private final int[] COMBAT_PORTAL_IDS = {6142, 6143, 6144, 6145, 6150, 6151, 6152, 6153};
        private final ArrayList<Integer> combatPortals = new ArrayList<Integer>();
        private final RSTile Location;
        private final String Name;
        private final RSTile gateLoc;

        public Portal(final RSTile t, final String name, final RSTile g) {
            Location = t;
            Name = name;
            gateLoc = g;

            for (final int i : COMBAT_PORTAL_IDS) {
                combatPortals.add(i);
            }
        }

        public boolean equals(final Portal p) {
            return p.getLocation().getX() == getLocation().getX()
                    && p.getLocation().getY() == getLocation().getY();
        }

        public RSArea getArea() {
            RSArea a = null;
            if (getName().equals("E")) {
                a = new RSArea(voidLoc.getX() + 24, voidLoc.getY() - 20, 3, 5);
            } else if (getName().equals("W")) {
                a = new RSArea(voidLoc.getX() - 25, voidLoc.getY() - 15, 4, 3);
            } else if (getName().contains("SE")) {
                a = new RSArea(voidLoc.getX() + 16, voidLoc.getY() - 34, 4, 3);
            } else if (getName().contains("SW")) {
                a = new RSArea(voidLoc.getX() - 8, voidLoc.getY() - 35, 5, 3);
            }
            return a;
        }

        public RSObject getGate() {
            return getTopObjectAt(getGateLocation());
        }

        public RSTile getGateLocation() {
            return gateLoc;
        }

        public RSTile getLocation() {
            return Location;
        }

        public String getName() {
            return Name;
        }

        public RSNPC getNPC() {
            if (!chckbxAttackBrawlers)
                return null;
            final RSNPC portal = getNearestNPCByName("Portal");
            if (portal != null) {
                if (combatPortals.contains(portal.getID()))
                    return portal;
                else
                    return null;
            }
            return null;
        }

        public RSTile getRandom() {
            final RSTile[][] tiles = getArea().getTiles();
            final int y = random(0, tiles.length - 1);
            final int x = random(0, tiles[y].length - 1);
            try {
                return tiles[x][y];
            } catch (final Exception e) {
                return getRandom();
            }
        }

        public RSArea getRealArea() {
            RSArea a = null;
            if (getName().equals("E")) {
                a = new RSArea(voidLoc.getX() + 16, voidLoc.getY() - 23, 14, 14);
            } else if (getName().equals("W")) {
                a = new RSArea(voidLoc.getX() - 30, voidLoc.getY() - 24, 16, 19);
            } else if (getName().contains("SE")) {
                a = new RSArea(voidLoc.getX(), voidLoc.getY() - 45, 28, 21);
            } else if (getName().contains("SW")) {
                a = new RSArea(voidLoc.getX() - 17, voidLoc.getY() - 44, 17, 20);
            }
            return a;
        }

        public boolean isGateOpen() {
            return getGate() == null || getGate().getID() > 14240;
        }

        public boolean isOpen() {
            try {
                if (getName().equals("W")) {
                    if (Integer.parseInt(getInterface(408, 13).getText()) < 10)
                        return false;
                }
                if (getName().equals("E")) {
                    if (Integer.parseInt(getInterface(408, 14).getText()) < 10)
                        return false;
                }
                if (getName().equals("SE")) {
                    if (Integer.parseInt(getInterface(408, 15).getText()) < 10)
                        return false;
                }
                if (getName().equals("SW")) {
                    if (Integer.parseInt(getInterface(408, 16).getText()) < 10)
                        return false;
                }
            } catch (final Exception e) {
                return false;
            }
            return true;
        }

        private void openGate() {
            while (inPest() && !isGateOpen()) {
                if (me.isMoving()) {
                    try {
                        Thread.sleep(random(500, 600));
                    } catch (final Exception e) {
                    }
                    continue;
                }
                final Point p = calc.tileToScreen(getGateLocation());
                if (!pointOnScreen(p)) {
                    walkTileMiniM(getGateLocation());
                    try {
                        Thread.sleep(random(500, 700));
                    } catch (final InterruptedException ignored) {
                    }
                    continue;
                }
                doAction(p, "Open");
            }
        }

        public void walkTo() {
            final Portal p = getNearestPortal();
            boolean died = false;
            final RSNPC npc = getNearestNPCByID(squire);
            if (npc != null) {
                if (distanceTo(npc) < 10) {
                    died = true;
                }
            }
            boolean atDoor = false;
            while (inPest() && distanceTo(getLocation()) > 10 && isOpen()) {
                if (me.isInCombat()
                        && me.getHPPercent() < 2
                        && distanceTo(getNearestNPCByID(squire)) > 15)
                    return;
                if (died) {
                    try {
                        Thread.sleep(random(300, 800));
                        setRun(true);
                        Thread.sleep(random(300, 800));
                        doDragonBattleAxe();
                        Thread.sleep(random(300, 800));
                    } catch (final Exception e) {
                    }
                    if (!atDoor) {
                        walkPath(genPath(getGateLocation()));
                        if (!isGateOpen() && tileOnScreen(getGateLocation())) {
                            openGate();
                            if (isGateOpen()) {
                                atDoor = true;
                            }
                        }
                        if (distanceTo(getGateLocation()) < 10 && isGateOpen()) {
                            atDoor = true;
                        }
                    }
                    if (atDoor) {
                        walkPath(genPath(getRandom()));
                    }
                } else if (p.getName().equals("E") && getName().equals("W")) {
                    while (inPest() && getNearestPortal().getName().equals("E")) {
                        final Portal se = getPortalByName("SE");
                        if (!walkPath(genPath(se.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (inPest()
                            && getNearestPortal().getName().equals("SE")) {
                        final Portal sw = getPortalByName("SW");
                        if (!walkPath(genPath(sw.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                } else if (p.getName().equals("W") && getName().equals("E")) {
                    while (inPest() && getNearestPortal().getName().equals("W")) {
                        final Portal sw = getPortalByName("SW");
                        if (!walkPath(genPath(sw.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (inPest()
                            && getNearestPortal().getName().equals("SW")) {
                        final Portal se = getPortalByName("SE");
                        if (!walkPath(genPath(se.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (!walkPath(genPath(getRandom()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("E") && getName().equals("SE")) {
                    if (!walkPath(genPath(getLocation()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("SE") && getName().equals("E")) {
                    while (!walkPath(genPath(getLocation()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("E") && getName().equals("SW")) {
                    while (inPest() && getNearestPortal().getName().equals("E")) {
                        final Portal se = getPortalByName("SE");
                        if (!walkPath(genPath(se.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (!walkPath(genPath(getRandom()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("SW") && getName().equals("E")) {
                    while (inPest()
                            && getNearestPortal().getName().equals("SW")) {
                        final Portal se = getPortalByName("SE");
                        if (!walkPath(genPath(se.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (!walkPath(genPath(getRandom()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("W") && getName().equals("SW")) {

                    if (!walkPath(genPath(getLocation()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("SW") && getName().equals("W")) {

                    if (!walkPath(genPath(getLocation()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("SE") && getName().equals("W")) {
                    while (inPest()
                            && getNearestPortal().getName().equals("SE")) {
                        final Portal se = getPortalByName("SW");
                        if (!walkPath(genPath(se.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (!walkPath(genPath(getRandom()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("W") && getName().equals("SE")) {

                    while (inPest() && getNearestPortal().getName().equals("W")) {
                        final Portal se = getPortalByName("SW");
                        if (!walkPath(genPath(se.getRandom()))) {
                            wait(400, 700);
                        }
                    }
                    while (!walkPath(genPath(getRandom()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("SW") && getName().equals("SE")) {

                    if (!walkPath(genPath(getLocation()))) {
                        wait(400, 700);
                    }
                } else if (p.getName().equals("SE") && getName().equals("SW")) {
                    if (!walkPath(genPath(getLocation()))) {
                        wait(400, 700);
                    }
                }
            }
        }

        public void wait(final int min, final int max) {
            try {
                Thread.sleep(random(min, max));
            } catch (final Exception ignored) {
            }
        }
    }
    private String status = "";
    private final LinkedList<Job> jobQ = new LinkedList<Job>();
    private final LinkedList<Portal> portalQ = new LinkedList<Portal>();
    private final LinkedList<Break> breakQ = new LinkedList<Break>();
    private final ArrayList<String> antibanQ = new ArrayList<String>();
    private Portal current;
    private boolean start = false;
    private final boolean chckbxAttackBrawlers = true;
    private boolean attackBrawlers = false;
    private boolean usePray = true;
    private boolean played = false;
    private boolean got250 = false;
    private boolean attackSpinner = true;
    private final boolean DBaxe = false;
    private final boolean pickupArrows = false;
    private RSTile[] path;
    private final int Interface_250 = 213;
    private int plankID = 14315;
    private final int squire = 3781;
    private int Squire;
    private int failsafe = 0;
    private int points = 0;
    private int specialPercent = 0;
    private int arrowID = 0;
    private int oldPoints = 0;
    private int gainedPoints = 0;
    private int lost = 0;
    private int won = 0;
    private RSArea boatArea = null;
    private RSTile voidLoc = null;
    private long lastAniChange = 0;
    private long startTime = 0;
    private long gc = 0;
    private final int ROTATE_COMPASS = 0;
    private final int MOVE_MOUSE = 1;
    private final int MOVE_MOUSE_AND_ROTATE_COMPASS = 2;
    private final int RIGHT_CLICK_OBJECT = 3;
    private final int RIGHT_CLICK_NPC = 4;
    private final int RIGHT_CLICK_PLAYER = 5;
    private final String[] jobsStrings = new String[]{"Attack", "Defence",
        "Magic", "Prayer", "Strength", "Ranged", "Hitpoints", "Top",
        "Robe", "Range Helm", "Melee Helm", "Mage Helm", "Glove"};
    private final int[] jobsPoints = new int[]{100, 100, 100, 100, 100, 100,
        100, 250, 250, 200, 200, 200, 150};
    private Break curBreak;
    private Pathfinder pf;
    private RSPlayer me = null;

    boolean allJobsFinished() {
        Job j = null;
        for (final Job job : jobQ) {
            if (!(j = job).isFinished()) {
                break;
            }
        }

        return j == null;
    }

    public void performAntiban(final String antiban) throws InterruptedException {
        log("Doing : " + antiban.toLowerCase().replace('_', ' '));
        final int ab = AntibanStringToInteger(antiban);
        switch (ab) {
            case ROTATE_COMPASS:
                char dir = 37;
                if (random(0, 3) == 2) {
                    dir = 39;
                }
                Bot.getInputManager().pressKey(dir);
                Thread.sleep(random(500, 2000));
                Bot.getInputManager().releaseKey(dir);
                break;
            case MOVE_MOUSE:
//                moveMouse(random(0, Canvas.getGameWidth()), random(0,
//                        Canvas.getGameHeight()));
                break;
            case MOVE_MOUSE_AND_ROTATE_COMPASS:
                final Thread camera = new Thread() {

                    @Override
                    public void run() {
                        char dir = 37;
                        if (random(0, 3) == 2) {
                            dir = 39;
                        }
                        Bot.getInputManager().pressKey(dir);
                        try {
                            Thread.sleep(random(500, 2000));
                        } catch (final InterruptedException e) {
                            e.printStackTrace();
                        }
                        Bot.getInputManager().releaseKey(dir);
                    }
                };

                final Thread mouse = new Thread() {

                    @Override
                    public void run() {
//                        moveMouse(random(0, Canvas.getGameWidth()), random(
//                                0, Canvas.getGameHeight()));
                    }
                };
                camera.start();
                mouse.start();
                while (camera.isAlive() || mouse.isAlive()) {
                    wait(random(100, 300));
                }
                break;
            case RIGHT_CLICK_OBJECT:
                final RSObject obj = getObjOnScreen();
                if (obj != null) {
                    clickMouse(calc.tileToScreen(obj.getLocation()), false);
                    Thread.sleep(random(500, 2000));
                    while (isMenuOpen()) {
                        moveMouseRandomly(20);
                    }
                }
                break;
            case RIGHT_CLICK_NPC:
                final RSNPC npc = getNPCOnScreen();
                if (npc != null) {
                    clickMouse(npc.getScreenLocation(), false);
                    Thread.sleep(random(500, 2000));
                    while (isMenuOpen()) {
                        moveMouseRandomly(20);
                    }
                }
                break;
            case RIGHT_CLICK_PLAYER:
                final RSPlayer player = getPlayerOnScreen();
                if (player != null) {
                    clickMouse(player.getScreenLocation(), false);
                    Thread.sleep(random(500, 2000));
                    while (isMenuOpen()) {
                        moveMouseRandomly(20);
                    }
                }
                break;
            default:
                break;
        }
    }

    public RSObject getObjOnScreen() {
        final ArrayList<RSObject> result = new ArrayList<RSObject>();
        for (int x = 0; x < 104; x++) {
            for (int y = 0; y < 104; y++) {
                final RSObject obj = getTopObjectAt(x + Bot.getClient().getBaseX(), y
                        + Bot.getClient().getBaseY());
                if (obj != null) {
                    final Point p = calc.tileToScreen(obj.getLocation());
                    if (p.x != -1) {
                        result.add(obj);
                    }
                }
            }
        }
        if (result.size() == 0)
            return null;
        return result.get(random(0, result.size()));
    }

    public RSNPC getNPCOnScreen() {
        final int[] validNpcs = Bot.getClient().getRSNPCIndexArray();
        final RSNPC[] npcs = getNPCArray(true);
        final ArrayList<RSNPC> p = new ArrayList<RSNPC>();
        for (final int element : validNpcs) {
            if (npcs[element] == null) {
                continue;
            }
            final RSNPC player = npcs[element];
            try {
                if (!tileOnScreen(player.getLocation())) {
                    continue;
                }
                p.add(player);
            } catch (final Exception ignored) {
            }
        }
        if (p.size() == 0)
            return null;
        else if (p.size() == 1)
            return p.get(0);
        return p.get(random(0, p.size() - 1));
    }

    public int AntibanStringToInteger(final String a) {
        if (a.contains("rotate compass"))
            return ROTATE_COMPASS;
        else if (a.contains("move mouse"))
            return MOVE_MOUSE;
        else if (a.contains("MOVE_MOUSE_AND_ROTATE_COMPASS".replaceAll("_", " ").toLowerCase()))
            return MOVE_MOUSE_AND_ROTATE_COMPASS;
        else if (a.contains("RIGHT_CLICK_OBJECT".replaceAll("_", " ").toLowerCase()))
            return RIGHT_CLICK_OBJECT;
        else if (a.contains("RIGHT_CLICK_NPC".replaceAll("_", " ").toLowerCase()))
            return RIGHT_CLICK_NPC;
        else if (a.contains("RIGHT_CLICK_PLAYER".replaceAll("_", " ").toLowerCase()))
            return RIGHT_CLICK_PLAYER;
        return -1;
    }

    public boolean arrayContains(final String[] array, final String option) {
        if (array == null)
            return false;
        for (final String s : array) {
            if (s.contains(option))
                return true;
        }
        return false;
    }

    boolean atPortal() {
        for (final Portal p : portalQ) {
            if (p.getRealArea().contains(me.getLocation()))
                return true;
        }
        return false;
    }

    public Break getCurrentBreak() {
        if ((curBreak == null || curBreak.isDone) && breakQ.size() == 0)
            return null;
        if (curBreak == null || curBreak.isDone) {
            curBreak = breakQ.remove();
        }
        if (curBreak.Time == null) {
            curBreak.init();
        }
        return curBreak;
    }

    boolean clickNPC(final RSNPC n, final String action) {
        enablePrayer();

        if (!tileOnScreen(n.getLocation())) {
            while (inPest() && atPortal()
                    && !walkPath(genPath(n.getLocation()))) {
                wait(random(200, 500));
            }
        }
        try {
            Point p = n.getScreenLocation();
            while ((p = n.getScreenLocation()) != null && p.x != -1
                    && getMouseLocation().distance(n.getScreenLocation()) > 8) {
                moveMouse(p, 5, 5);
            }
            if (!pointOnScreen(getMouseLocation()))
                return false;

            if (getTopText().contains(action)) {
                clickMouse(true);
            } else if (menuContains(action)) {
                clickMouse(false);
                return atMenu(action);
            } else
                return false;
        } catch (final Exception ignored) {
        }
        return true;
    }

    @Override
    public int getMouseSpeed() {
        return random(5, 7);
    }

    void clickRandomPlayer() {
        RSPlayer p;
        if ((p = getPlayerOnScreen()) != null) {
            if (p.getScreenLocation().x != -1 && p.getScreenLocation().y != -1) {
                moveMouse(p.getScreenLocation());
                clickMouse(false);
                wait(random(800, 1000));
                moveMouse(random(0, 763), random(0, 503));
            }
        }
    }

    boolean doAction(final Point p, final String action) {
        if (p.x == -1 || p.y == -1)
            return false;
        while (p.x != -1 && getMouseLocation().distance(p) > 8) {
            moveMouse(p);
        }
        if (!pointOnScreen(getMouseLocation()))
            return false;
        if (getTopText().contains(action)) {
            clickMouse(true);
        } else if (menuContains(action)) {
            clickMouse(false);
            return atMenu(action);
        } else
            return false;
        return true;
    }

    void doJob() {
        final Job j = getJob();
        if (j == null)
            return;
        if (j.points == 250 && !got250)
            return;
        if (j.points >= points)
            return;
        while (!getInterface(267).isValid() || getInterface(267).isValid()
                && getInterface(267, 34).getAbsoluteX() < 10) {
            if (me.getInteracting() != null) {
                continue;
            }
            if (getNearestNPCByID(3788) == null) {
                walkPath(genPath(new RSTile(2661, 2650)), 2);
            } else if (distanceTo(getNearestNPCByID(3788)) > 3) {
                walkPath(genPath(getNearestNPCByID(3788).getLocation()), 2);
            }
            if (clickNPC(getNearestNPCByID(3788), "Exchange")) {
                wait(random(800, 1200));
            } else {
                wait(random(300, 700));
            }
        }
        wait(random(800, 1000));
        int i = 0;
        boolean skip = false;
        ;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(188, 223), random(67, 72), true);
            skip = true;
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(188, 223), random(104, 112), true);
            skip = true;
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(188, 223), random(144, 151), true);
            skip = true;
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(188, 223), random(180, 188), true);
            skip = true;
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(406, 444), random(67, 72), true);
            skip = true;
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(406, 444), random(104, 112), true);
            skip = true;
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(406, 444), random(144, 151), true);
            skip = true;
        }
        if (!skip) {
            clickMouse(481, 179, true);
            wait(random(800, 900));
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(300, 340), random(111, 119), true);
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(80, 120), random(150, 155), true);
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(300, 340), random(190, 197), true);
        }
        i++;

        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(80, 120), random(188, 193), true);
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(80, 120), random(225, 234), true);
        }
        i++;
        if (j.getName().equals(jobsStrings[i])) {
            clickMouse(random(300, 340), random(151, 156), true);
        }
        jobQ.remove(j);
        wait(random(800, 1000));
        clickMouse(random(190, 320), random(285, 320), true);
        oldPoints = 0;
        played = false;
        points = 0;
        got250 = false;
    }

    @Override
    public boolean tileOnMap(final RSTile tile) {
        final Point center = tileToMinimap(getLocation());
        return tileToMinimap(tile).distance(center) <= 70;
    }

    void enablePrayer() {
        if (!PrayerEnabled() && skills.getCurrSkillLevel(STAT_PRAYER) > 0 && usePray) {
            atInterface(INTERFACE_PRAYER_ORB, 0);
            //clickMouse(random(715, 752), random(60, 80), true);
        }
    }

    void disablePrayer() {
        if (PrayerEnabled() && skills.getCurrSkillLevel(STAT_PRAYER) > 0 && usePray) {
            atInterface(INTERFACE_PRAYER_ORB, 0);
            //clickMouse(random(715, 752), random(60, 80), true);
        }
    }

    int enterBoat() {
        portalQ.clear();
        final RSObject o = getPlank();
        if (o != null && !onBoat()) {
            final RSTile t = o.getLocation();
            final Point p = calc.tileToScreen(t);
            if (p.x == -1 || p.y == -1) {
                walkTileMiniM(t);
            }
            if (doAction(p, "Cross"))
                return random(1000, 1300);
        }
        return random(600, 800);
    }

    RSObject getPlank() {
        for (int x = 0; x < 104; x++) {
            for (int y = 0; y < 104; y++) {
                final RSObject obj = getTopObjectAt(x + Bot.getClient().getBaseX(), y
                        + Bot.getClient().getBaseY());
                if (obj != null && obj.getID() == plankID)
                    return obj;
            }
        }
        return null;
    }

    void fillPortalList() {
        if (portalQ.size() < 1) {
            portalQ.add(new Portal(new RSTile(voidLoc.getX() - 26, voidLoc.getY() - 15), "W", new RSTile(voidLoc.getX() - 12, voidLoc.getY() - 15)));
            portalQ.add(new Portal(new RSTile(voidLoc.getX() + 26, voidLoc.getY() - 18), "E", new RSTile(voidLoc.getX() + 15, voidLoc.getY() - 15)));
            portalQ.add(new Portal(new RSTile(voidLoc.getX() + 15, voidLoc.getY() - 36), "SE", new RSTile(voidLoc.getX() + 1, voidLoc.getY() - 22)));
            portalQ.add(new Portal(new RSTile(voidLoc.getX() - 9, voidLoc.getY() - 37), "SW", new RSTile(voidLoc.getX() + 1, voidLoc.getY() - 22)));
        } else {
            portalQ.clear();
            fillPortalList();
        }
    }

    RSTile[] genPath(final RSTile t) {
        final RSTile[] temp = pf.findPath(t);
        if (temp != null)
            return temp;
        RSTile current = me.getLocation();
        final ArrayList<RSTile> tiles = new ArrayList<RSTile>();
        final ArrayList<RSTile> path = new ArrayList<RSTile>();

        while (Methods.distanceBetween(t, current) > 2) {
            final int x = current.getX();
            final int y = current.getY();
            tiles.add(new RSTile(x, y - 1));
            tiles.add(new RSTile(x - 1, y));
            tiles.add(new RSTile(x + 1, y));
            tiles.add(new RSTile(x, y + 1));
            tiles.add(new RSTile(x - 1, y - 1));
            tiles.add(new RSTile(x + 1, y - 1));
            tiles.add(new RSTile(x + 1, y + 1));
            tiles.add(new RSTile(x - 1, y + 1));
            final RSTile tile = getNearest(tiles, t);
            path.add(tile);
            this.path = path.toArray(new RSTile[path.size()]);
            current = tile;
            tiles.clear();
        }
        this.path = path.toArray(new RSTile[path.size()]);
        return this.path;
    }

    Portal getCurrentPortal() {
        return current;
    }

    Job getJob() {
        if (jobQ.size() == 0)
            return null;
        return jobQ.getFirst();
    }

    RSTile getNearest(final ArrayList<RSTile> tiles, final RSTile t) {
        RSTile nearest = tiles.get(0);
        for (final RSTile tile : tiles) {
            if (Methods.distanceBetween(tile, t) < Methods.distanceBetween(
                    nearest, t)) {
                nearest = tile;
            }
        }
        return nearest;
    }

    Portal getNearestOpenPortal() {
        if (portalQ.size() < 1)
            return null;
        Portal winner = null;
        for (final Portal p : portalQ) {
            if (p.isOpen()) {
                winner = p;
            }
        }
        if (winner == null)
            return null;

        for (final Portal p : portalQ) {
            if (!p.isOpen()) {
                continue;
            }
            if (distanceTo(p.getLocation()) < distanceTo(winner.getLocation())) {
                winner = p;
            }
        }
        current = winner;
        return winner;
    }

    Portal getNearestPortal() {
        if (portalQ.size() < 1)
            return null;
        Portal winner = portalQ.get(0);
        for (final Portal p : portalQ) {
            if (distanceTo(p.getLocation()) < distanceTo(winner.getLocation())) {
                winner = p;
            }
        }
        return winner;
    }

    RSTile getNext(final RSTile[] path) {
        RSTile nearest = path[0];
        for (final RSTile element : path) {
            if (Methods.distanceBetween(element, path[path.length - 1]) < Methods.distanceBetween(nearest, path[path.length - 1])) {
                if (tileOnMap(element)) {
                    nearest = element;
                }
            }
        }
        return nearest;
    }

    RSPlayer getPlayerOnScreen() {
        final int[] validPlayers = Bot.getClient().getRSPlayerIndexArray();
        final org.rsbot.client.RSPlayer[] players = Bot.getClient().getRSPlayerArray();
        final ArrayList<RSPlayer> p = new ArrayList<RSPlayer>();
        for (final int element : validPlayers) {
            if (players[element] == null) {
                continue;
            }
            final RSPlayer player = new RSPlayer(players[element], getBot());
            try {
                if (!tileOnScreen(player.getLocation())) {
                    continue;
                }
                p.add(player);
            } catch (final Exception ignored) {
            }
        }
        if (p.size() == 0)
            return null;
        else if (p.size() == 1)
            return p.get(0);
        return p.get(random(0, p.size() - 1));
    }

    Portal getPortalByName(final String name) {
        if (portalQ.size() < 1)
            return null;
        for (final Portal p : portalQ) {
            if (p.getName().equalsIgnoreCase(name))
                return p;
        }
        return null;
    }

    public RSTile getRandom(final RSArea a) {
        try {
            final RSTile[][] tiles = a.getTiles();
            final int y = random(0, tiles.length - 1);
            final int x = random(0, tiles[y].length - 1);
            return tiles[x][y];
        } catch (final Exception ignored) {
        }
        return new RSTile(-1, -1);
    }

    Portal getRandomOpenPortal() {
        if (portalQ.size() < 1)
            return null;
        final ArrayList<Portal> po = new ArrayList<Portal>();
        for (final Portal p : portalQ) {
            if (p.isOpen()) {
                po.add(p);
            }
        }
        current = po.get(random(0, po.size()));
        return current;
    }

    String getTopText() {
        try {
            final long start = System.currentTimeMillis();
            String[] menuItems = getMenuItems().toArray(
                    new String[getMenuItems().size()]);
            if (menuItems.length == 0)
                return "Cancel";
            while (menuItems[0].contains("Cancel")
                    && pointOnScreen(getMouseLocation())
                    && System.currentTimeMillis() - start < 700) {
                menuItems = getMenuItems().toArray(
                        new String[getMenuItems().size()]);
            }
            return menuItems[0];
        } catch (final Exception e) {
            return getTopText();
        }
    }

    boolean inPest() {
        return getNearestNPCByID(Squire) == null;
    }

    @Override
    public int loop() {
        try {
            if (gc == 0) {
                gc = System.currentTimeMillis();
            }

            if (!onBoat() && !inPest()) {
                final Break b = getCurrentBreak();
                if (b != null && b.needsBreak()) {
                    b.takeBreak();
                }
            }

            if (this.getInterface(Interface_250).isValid()) {
                got250 = true;
            }

            if (me.isInCombat() && me.getHPPercent() < 2
                    && distanceTo(getNearestNPCByID(squire)) > 15)
                return random(600, 800);

            if (!onBoat() && !inPest() && getJob() != null) {
                doJob();
            }

            if (getJob() == null && got250) {
                logout();
                log("Thanks for using BPestControll");
                log("Reached 250 points and out of jobs");
            }
            if (isMenuOpen()) {
                status = "Closing menu";
                moveMouse(random(5, 760), random(5, 500));
            }
            if (!inPest() && !onBoat()) {
                status = "Entering boat";
                return enterBoat();
            }
            if (onBoat()) {
                status = "On boat";
                String s = "";
                if (getInterface(407, 16) != null) {
                    s = getInterface(407, 16).getText();
                }
                points = Integer.parseInt(s.replace("Pest Points: ", ""));
                if (played) {
                    if (points > oldPoints) {
                        gainedPoints += points - oldPoints;
                    }
                    if (points - oldPoints == 0) {
                        lost++;
                    } else {
                        won++;
                    }
                }
                oldPoints = points;
                played = false;
                return random(400, 700);
            }
            if (getNearestNPCByID(squire) != null) {
                voidLoc = getNearestNPCByID(squire).getLocation();
                fillPortalList();
            }
            if (inPest())
                return pestLoop();
        } catch (final Exception ignored) {
        }
        return random(100, 800);
    }

    @Override
    public boolean menuContains(final String a) {
        try {
            final long start = System.currentTimeMillis();
            String[] menuItems = getMenuItems().toArray(
                    new String[getMenuItems().size()]);
            while (menuItems[0].contains("Cancel")
                    && pointOnScreen(getMouseLocation())
                    && System.currentTimeMillis() - start < 700) {
                menuItems = getMenuItems().toArray(
                        new String[getMenuItems().size()]);
            }
            for (final String element : menuItems) {
                if (element.contains(a))
                    return true;
            }
        } catch (final Exception ignored) {
        }
        return false;
    }

    @Override
    public void moveMouse(final int x, final int y) {
        if (x != -1 && y != -1) {
            moveMouse(x, y, 0, 0);
        }
    }

    @Override
    public void moveMouse(final Point p) {
        if (p.x != -1 && p.y != -1) {
            moveMouse(p.x, p.y, 0, 0);
        }
    }

    @Override
    public void moveMouse(final Point p, final int rX, final int rY) {
        final int X = p.x + random(-(rX / 2), (rX / 2));
        final int Y = p.y + random(-(rY / 2), (rY / 2));
        moveMouse(X, Y);
    }

    boolean onBoat() {
        return boatArea != null
                && boatArea.contains(me.getLocation());
    }

    @Override
    public void onFinish() {
        log("Gained " + gainedPoints + " points.");
    }
    int width = 0;
    int height = 0;

    public void onRepaint(final Graphics g) {
        if (getCurrentBreak() != null) {
            g.drawString(getCurrentBreak().getTimeTillBreak(), 10, 400);
            g.drawString("" + getCurrentBreak().needsBreak(), 10, 415);
        }
        final int baseY = 350;
        int y = baseY;
        final int x = 537;

        g.setColor(new Color(51, 153, 255, 170));
        g.fillRoundRect(x - 5, baseY, width, height, 5, 5);
        g.setColor(Color.WHITE);
        g.drawRoundRect(x - 5, baseY, width, height, 5, 5);

        width = 0;
        height = 0;
        if (startTime == 0) {
            startTime = System.currentTimeMillis();
        }
        final long millis = System.currentTimeMillis() - startTime;
        try {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", Font.BOLD, 14));
            g.drawString("BPestControlV2 by Bool", x, y += g.getFontMetrics().getHeight());
            height += g.getFontMetrics().getHeight();
            width = (int) g.getFontMetrics().getStringBounds(
                    "BPestControlV2 made by Bool", g).getWidth();


            g.setFont(new Font("Arial", Font.PLAIN, 12));
            g.drawString("      updated by zzSleepzz", x, y += g.getFontMetrics().getHeight());
            height += g.getFontMetrics().getHeight();

            g.drawString("Lost " + lost + " Games", x, y += g.getFontMetrics().getHeight());
            height += g.getFontMetrics().getHeight();
            g.drawString("won " + won + " Games", x, y += g.getFontMetrics().getHeight());
            height += g.getFontMetrics().getHeight();
            g.drawString("Gained " + gainedPoints + " points", x, y += g.getFontMetrics().getHeight());
            height += g.getFontMetrics().getHeight();
            g.drawString("Time running : " + timeToString(millis), x, y += g.getFontMetrics().getHeight());
            height += g.getFontMetrics().getHeight();
            if (getJob() != null) {
                if (g.getFontMetrics().getStringBounds(
                        "Spending points on " + getJob().getName(), g).getWidth() > width) {
                    width = (int) g.getFontMetrics().getStringBounds(
                            "Spending points on " + getJob().getName(), g).getWidth();
                }
                g.drawString("Spending points on " + getJob().getName() + " "
                        + points, x, y += g.getFontMetrics().getHeight());
                height += g.getFontMetrics().getHeight();
            }

            height += g.getFontMetrics().getHeight();
            g.drawString("Status : " + status, x, y += g.getFontMetrics().getHeight());

            height += 5;
            width += 10;
        } catch (final Exception ignored) {
        }
    }

    @Override
    public boolean onStart(final Map<String, String> l) {
        start = false;
        final BGUI gui = new BGUI();
        gui.setVisible(true);

        status = "Waiting for GUI";
        while (gui.isVisible()) {
            wait(random(500, 600));
        }
        if (!start)
            return false;
        else {

            while (!isLoggedIn()) {
                wait(500);
            }

            me = getMyPlayer();

            final RSNPC npc = getNearestNPCByID(SQUIRE_NOVICE, SQUIRE_INTERMED, SQUIRE_VETERAN);
            if (npc != null) {
                if (npc.getID() == SQUIRE_NOVICE) {
                    plankID = 14315;
                    boatArea = new RSArea(2660, 2638, 3, 5);
                    Squire = SQUIRE_NOVICE;
                } else if (npc.getID() == SQUIRE_INTERMED) {
                    plankID = 25631;
                    boatArea = new RSArea(2638, 2642, 3, 5);
                    Squire = SQUIRE_INTERMED;
                } else if (npc.getID() == SQUIRE_VETERAN) {
                    plankID = 25632;
                    boatArea = new RSArea(2631, 2648, 5, 7);
                    Squire = SQUIRE_VETERAN;
                }
            } else
                return false;

            new Thread(new animationChecker()).start();
            antiban.start();
        }
        status = "Script started";
        log("starting script");
        pf = new Pathfinder();
        return start;
        // return true;
    }

    int pestLoop() {
        if (!played) {
            played = true;
        }
        try {
            if (!atPortal()) {
                status = "Not at portal, walking to portal";
                disablePrayer();
                final Portal p = getRandomOpenPortal();
                avoidBrawler(p.getNPC());
                p.walkTo();
                return random(100, 600);
            }
            if (!getCurrentPortal().equals(getNearestPortal()) || !getCurrentPortal().isOpen()) {
                if (getNearestOpenPortal() != null) {
                    status = "Walking to portal";
                    disablePrayer();
                    final Portal p = getNearestOpenPortal();
                    avoidBrawler(p.getNPC());
                    p.walkTo();
                }
                return random(100, 600);
            }

            checkSpecial();

            final RSCharacter inter = me.getInteracting();
            boolean attackingPortal = false;
            boolean attackingSpinner = false;

            if (inter != null) {
                attackingPortal = inter.getName().toLowerCase().contains("portal");
                attackingSpinner = inter.getName().toLowerCase().contains("spinner");
            }

            if (inter == null) {
                status = "Not interacting";

                final RSItemTile t = getGroundItem(arrowID);

                if (t != null && t.isValid()) {
                    status = "Taking arrows.";
                    atTile(t, "Take");
                    return random(600, 800);
                }
                path = null;
                if (!inPest()) {
                    status = "Game ended";
                    return random(100, 500);
                }

                failsafe = 0;
            }

            if (attackingPortal || attackingSpinner)
                return random(300, 500);

            RSNPC c = getNPC();
            final RSNPC p = getCurrentPortal().getNPC();

            if (c != null && !c.getName().toLowerCase().contains("spinner") && p != null) {
                c = p;
            }

            if (c != null) {
                // Avoid brawler logic from SmarterPCDivi
                if ((c.getName().toLowerCase().contains("spinner")
                        || c.getName().toLowerCase().contains("portal")) && distanceTo(c.getLocation()) < 5) {
                    avoidBrawler(c);

                    if (clickNPC(c, "Attack")) {
                        status = "Attacking " + c.getName();
                    }

                    return random(600, 900);
                } else if (me.getInteracting() == null) {
                    if (clickNPC(c, "Attack")) {
                        status = "Attacking " + c.getName();
                    }
                }
                return random(600, 900);
            }

            /*
            RSNPC n = getNPC(true);
            if (n != null && n.getName().contains("Spinner")) {
            RSNPC inter = (RSNPC) me.getInteracting();
            if ((inter != null && !inter.getName().equals(n.getName()))
            || inter == null)
            if (clickNPC(n, "Attack")) {
            status = "Attacking " + n.getName();
            return random(600, 1200);
            }
            }
             */
            path = null;
            if (failsafe > 4) {
                status = "Failsafe, walking to portal.";
                walkTileMiniM(getNearestOpenPortal().getRandom());
            }
            final RSNPC npc = (RSNPC) me.getInteracting();
            if (me.isMoving()
                    || me.getInteracting() != null
                    || System.currentTimeMillis() - lastAniChange < 2000
                    || npc != null && npc.getName().contains("ortal")) {
                failsafe = 0;
            } else {
                failsafe++;
                wait(random(600, 800));
            }
            return random(400, 700);
        } catch (final Exception ignored) {
        }
        return random(400, 700);
    }

    boolean PrayerEnabled() {
        return getSetting(1395) > 0;
    }
    private int i = 0;

    boolean walkPath(final RSTile[] path) {
        final char left = 37;
        final char right = 39;
        final RSTile tile = getNext(path);
        moveMouse(calc.worldToMinimap(tile.getX(), tile.getY()));
        if (!inPest())
            return true;
        if (i == 7) {
            final char dir = random(0, 3) == 2 ? left : right;
            Bot.getInputManager().pressKey(dir);
            wait(random(800, 1200));
            Bot.getInputManager().releaseKey(dir);
            i = 0;
            return false;
        }
        if (getTopText().contains("ancel")) {
            i++;
            return false;
        }
        try {
            walkTileMiniM(getNext(path));
            wait(random(200, 500));
            while (me.isMoving() && distanceTo(getDestination()) > 7) {
                wait(random(600, 800));
            }
        } catch (final Exception ignored) {
        }
        return distanceTo(path[path.length - 1]) < 10 || !inPest();
    }

    void checkSpecial() {
        if (specialPercent == 0 || isSpecialEnabled())
            return;
        final int percent = (getSetting(300) / 10);
        if (percent > specialPercent) {
            final RSInterfaceChild child = ifaces.getChildInterface(884, 4);
            if (getCurrentTab() != TAB_ATTACK) {
                openTab(TAB_ATTACK);
            }
            atInterface(child);
            wait(random(400, 700));
        }
    }

    boolean isSpecialEnabled() {
        return getSetting(301) == 1;
    }

    void walkPath(final RSTile[] path, final int i) {
        try {
            walkTileMiniM(getNext(path));
            wait(random(200, 500));
            while (me.isMoving() && distanceTo(getDestination()) > 7) {
                wait(random(600, 800));
            }
        } catch (final Exception ignored) {
        }
    }
    int daxeID = 0;
    int oldID = 0;

    public void doDragonBattleAxe() {
        if (!DBaxe)
            return;
        if (getCurrentTab() != TAB_INVENTORY) {
            openTab(TAB_INVENTORY);
        }
        atInventoryItem(daxeID, "");
        if (getCurrentTab() != TAB_ATTACK) {
            openTab(TAB_ATTACK);
        }
        final RSInterfaceChild child = ifaces.getChildInterface(884, 4);
        atInterface(child);
        wait(random(1200, 1500));
        if (getCurrentTab() != TAB_INVENTORY) {
            openTab(TAB_INVENTORY);
        }
        atInventoryItem(oldID, "");

    }

    RSNPC getNPC() {
        final String[] names = {"Shifter", "Defiler", "Torcher", "Brawler",
            "Ravager", "Spinner"};
        RSNPC closest = null;
        final RSNPC[] npcs = getNPCArray(true);
        final ArrayList<RSNPC> result = new ArrayList<RSNPC>();

        debug("Getting an NPC");
        for (int element = 0; element < npcs.length; element++) {
            if (npcs[element] == null) {
                continue;
            }

            final RSNPC Monster = npcs[element];
            final String nm = Monster.getName();
            if (!attackBrawlers && nm.toLowerCase().contains("brawler")) {
                continue;
            }
            if (!attackSpinner && nm.toLowerCase().contains("spinner")) {
                continue;
            }

            debug("checking " + Monster.getName());

            try {
                for (final String name : names) {
                    debug("checking " + name + " " + Monster.getName());
                    if (!name.equals(Monster.getName())
                            || distanceBetween(
                            getCurrentPortal().getLocation(), Monster.getLocation()) > 10
                            || Monster.isInCombat()
                            && Monster.getHPPercent() < 10) {
                        continue;
                    }
                    debug("Found a monster");
                    result.add(Monster);
                }

                debug("NPC 2");
            } catch (final Exception e) {
                debug("Exception occurred.");
                e.printStackTrace();
            }
        }

        debug("NPC 3");
        if (result.size() == 0) {
            debug("No npcs found");
            return null;
        }

        RSNPC s = null;
        debug("Getting nearest spinner or other npc");
        for (final RSNPC npc : result) {
            if (attackSpinner) {
                if (npc.getName().equalsIgnoreCase("Spinner")) {
                    if (s == null || distanceTo(s) > distanceTo(npc)) {
                        debug("have a spinner");
                    }
                    s = npc;
                }
            }
            if (closest == null || distanceTo(closest) > distanceTo(npc)) {
                closest = npc;
            }
        }
        if (attackSpinner && s != null) {
            debug("..Returning spinner");
            return s;
        }

        debug("..Returning closest NPC: " + closest.getName());
        return closest;
    }

    class Break {

        public boolean isDone = false;
        int time, after;
        public Timer Time;
        long end;

        public Break(final int time, final int after) {
            this.time = time;
            this.after = after;
            end = System.currentTimeMillis() + after;
        }

        public void init() {
            Time = new Timer(time);
            end = System.currentTimeMillis() + after;
        }

        public void takeBreak() {
            while (isLoggedIn()) {
                logout();
            }
            Time.reset();
            log("Taking break for " + Time.toString());
            while (!Time.isDone()) {
                try {
                    Thread.sleep(random(500, 800));
                } catch (final InterruptedException e) {
                }
            }
            isDone = true;
        }

        public String getTimeTillBreak() {
            return timeToString(end - System.currentTimeMillis());
        }

        public boolean needsBreak() {
            return System.currentTimeMillis() > end;
        }
    }

    class Timer {

        private long start;
        private final int time;

        public Timer(final int time) {
            start = System.currentTimeMillis();
            this.time = time;
        }

        public Timer() {
            this(0);
        }

        public boolean isDone() {
            return (System.currentTimeMillis() - start) > time;
        }

        public void reset() {
            start = System.currentTimeMillis();
        }

        @Override
        public String toString() {
            return timeToString((System.currentTimeMillis() - start));
        }

        public String timeRemaining() {
            return timeToString(((System.currentTimeMillis() - start) + time));
        }
    }

    public String timeToString(long time) {
        final long hours = time / (1000 * 60 * 60);
        time -= hours * 1000 * 60 * 60;
        final long minutes = time / (1000 * 60);
        time -= minutes * 1000 * 60;
        final long seconds = time / 1000;
        String str = "";
        if (hours < 10) {
            str += "0";
        }
        str += hours + ":";
        if (minutes < 10) {
            str += "0";
        }
        str += minutes + ":";
        if (seconds < 10) {
            str += "0";
        }
        str += seconds;
        return str;
    }

    Thread antiban = new Thread() {

        @Override
        public void run() {
            setName("Antiban");
            while (isActive) {
                try {
                    if (!isLoggedIn()) {
                        Thread.sleep(300, 400);
                        continue;
                    }
                    final int i = random(0, 150);
                    if (i == 4 || i == 9) {
                        performAntiban(antibanQ.get(random(0, antibanQ.size())));
                    }
                    sleep(random(100, 2000));
                } catch (final InterruptedException ignored) {
                }
            }
        }
    };

    class Pathfinder {

        public int basex, basey;
        public int[][] blocks;

        public Pathfinder() {
            reload();
        }

        public void reload() {
            basex = Bot.getClient().getBaseX();
            basey = Bot.getClient().getBaseY();
            blocks = Bot.getClient().getRSGroundDataArray()[Bot.getClient().getPlane()].getBlocks();
        }

        public RSTile[] findPath(final RSTile dest) {
            if (!isValid()) {
                reload();
            }
            return findPath(getLocation(), dest);
        }

        public RSTile[] findPath(final RSTile start, final RSTile dest) {
            if (!isValid()) {
                reload();
            }
            return findPath(
                    new Node(start.getX() - basex, start.getY() - basey),
                    new Node(dest.getX() - basex, dest.getY() - basey));
        }

        public RSTile[] findPath(final Node start, final Node dest) {
            if (!isValid()) {
                reload();
            }
            if (!canReach(new RSTile(dest.x + basex, dest.y + basey), false))
                return null;
            final ArrayList<Node> closed = new ArrayList<Node>();
            final ArrayList<Node> open = new ArrayList<Node>();

            Node current = start;
            open.add(current);
            while (open.size() != 0) {
                current = getBestNode(open);
                closed.add(current);
                open.remove(current);
                for (final Node node : getNodesAround(current)) {
                    if (!closed.contains(node)) {
                        if (!open.contains(node)) {
                            node.parent = current;
                            node.cost = current.cost
                                    + getMovementCost(node, current);
                            node.heuristic = node.cost
                                    + getHeuristicCost(node, dest);
                            open.add(node);
                        } else {
                            if (current.cost + getMovementCost(node, current) < node.cost) {
                                node.parent = current;
                                node.cost = current.cost
                                        + getMovementCost(node, current);
                                node.heuristic = node.cost
                                        + getHeuristicCost(node, dest);
                            }
                        }
                    }
                }
                if (closed.contains(dest)) {
                    final ArrayList<RSTile> result = new ArrayList<RSTile>();
                    Node node = closed.get(closed.size() - 1);
                    while (node.parent != null) {
                        result.add(new RSTile(node.x + basex, node.y + basey));
                        node = node.parent;
                    }
                    path = reversePath(result.toArray(new RSTile[result.size()]));
                    return path;
                }
            }
            return null;
        }

        public Node getBestNode(final ArrayList<Node> nodes) {
            Node winner = null;
            for (final Node node : nodes) {
                if (winner == null || node.cost < winner.cost) {
                    winner = node;
                }
            }
            return winner;
        }

        public double getHeuristicCost(final Node current, final Node dest) {
            final float dx = dest.x - current.x;
            final float dy = dest.y - current.y;
            return (Math.sqrt((dx * dx) + (dy * dy)));
        }

        public double getMovementCost(final Node current, final Node dest) {
            return Math.hypot(dest.x - current.x, dest.y - current.y);
        }

        /**
         * credits to jacmob
         */
        public ArrayList<Node> getNodesAround(final Node node) {
            final ArrayList<Node> tiles = new ArrayList<Node>();
            final int curX = node.x, curY = node.y;
            if (curX > 0 && curY < 103
                    && (blocks[curX - 1][curY + 1] & 0x1280138) == 0
                    && (blocks[curX - 1][curY] & 0x1280108) == 0
                    && (blocks[curX][curY + 1] & 0x1280120) == 0) {
                tiles.add(new Node(curX - 1, curY + 1));
            }
            if (curY < 103 && (blocks[curX][curY + 1] & 0x1280120) == 0) {
                tiles.add(new Node(curX, curY + 1));
            }
            if (curX > 0 && curY < 103
                    && (blocks[curX - 1][curY + 1] & 0x1280138) == 0
                    && (blocks[curX - 1][curY] & 0x1280108) == 0
                    && (blocks[curX][curY + 1] & 0x1280120) == 0) {
                tiles.add(new Node(curX + 1, curY + 1));
            }
            if (curX > 0 && (blocks[curX - 1][curY] & 0x1280108) == 0) {
                tiles.add(new Node(curX - 1, curY));
            }
            if (curX < 103 && (blocks[curX + 1][curY] & 0x1280180) == 0) {
                tiles.add(new Node(curX + 1, curY));
            }
            if (curX > 0 && curY > 0
                    && (blocks[curX - 1][curY - 1] & 0x128010e) == 0
                    && (blocks[curX - 1][curY] & 0x1280108) == 0
                    && (blocks[curX][curY - 1] & 0x1280102) == 0) {
                tiles.add(new Node(curX - 1, curY - 1));
            }
            if (curY > 0 && (blocks[curX][curY - 1] & 0x1280102) == 0) {
                tiles.add(new Node(curX, curY - 1));
            }
            if (curX < 103 && curY > 0
                    && (blocks[curX + 1][curY - 1] & 0x1280183) == 0
                    && (blocks[curX + 1][curY] & 0x1280180) == 0
                    && (blocks[curX][curY - 1] & 0x1280102) == 0) {
                tiles.add(new Node(curX + 1, curY - 1));
            }
            return tiles;

        }

        public boolean validTile(final RSTile tile) {
            if (!isValid()) {
                reload();
            }
            final int x = tile.getX() - basex;
            final int y = tile.getY() - basey;
            return x > 0 && x < 105 && y > 0 && y < 105;
        }

        public boolean isValid() {
            return basex == Bot.getClient().getBaseX()
                    && basey == Bot.getClient().getBaseY();
        }

        class Node {

            public final int x, y;
            public double cost = 0, heuristic = 0;
            public Node parent;

            public Node(final int x, final int y) {
                this.x = x;
                this.y = y;
            }

            @Override
            public boolean equals(final Object other) {
                if (other instanceof Node) {
                    final Node o = (Node) other;
                    return x == o.x && y == o.y;
                }
                return false;
            }
        }
    }

    public int avoidBrawler(final RSNPC temp) {
        if (temp == null)
            return random(100, 300);
        final RSNPC brawler = getNearestNPCByName("Brawler");
        if (brawler == null)
            return -1;
        final RSTile brawl = brawler.getLocation();
        final int bX = brawl.getX();
        final int bY = brawl.getY();
        RSTile player = me.getLocation();
        int pX = player.getX();
        int pY = player.getY();
        final RSTile attack = temp.getLocation();
        final int aX = attack.getX();
        final int aY = attack.getY();
        if (distanceTo(brawler) < 2) {
            if (pX == bX + 1 || pX == bX - 1 || pX == bX) {
                if (pX == aX || pX == aX + 1 || pX == aX - 1) {
                    status = "Avoiding brawler";
                    final RSTile to = new RSTile(pX + random(3, 4), pY);
                    walkTileOnScreen(to);
                    while (me.isMoving()) {
                        wait(random(500, 900));
                    }
                    final RSTile monst = temp.getLocation();
                    final int tY = monst.getY();
                    player = me.getLocation();
                    pX = player.getX();
                    final RSTile too = new RSTile(pX, tY);
                    walkTileOnScreen(too);
                    wait(random(1000, 1100));
                    while (me.isMoving()) {
                        wait(random(500, 900));
                    }
                    walkTileOnScreen(monst);
                    while (me.isMoving()) {
                        wait(random(500, 900));
                    }
                    return random(100, 300);
                }
            }
            if (pY == bY + 1 || pY == bY - 1 || pY == bY) {
                if (pY == aY || pY == aY + 1 || pY == aY - 1) {
                    status = "Avoiding brawler";
                    final RSTile to = new RSTile(pX, pY + random(3, 4));
                    walkTileOnScreen(to);
                    wait(random(1000, 1100));
                    while (me.isMoving()) {
                        wait(random(500, 900));
                    }
                    final RSTile monst = temp.getLocation();
                    final int tX = monst.getX();
                    player = me.getLocation();
                    pY = player.getY();
                    final RSTile too = new RSTile(tX, pY);
                    walkTileOnScreen(too);
                    while (me.isMoving()) {
                        wait(random(500, 900));
                    }
                    walkTileOnScreen(monst);
                    while (me.isMoving()) {
                        wait(random(500, 900));
                    }
                    return random(20, 100);
                }
                return random(100, 300);
            }
            return random(100, 300);
        }
        return random(10, 20);
    }
}